#include "Acceptor.h"
#include "TcpConnection.h"
#include "EventLoop.h"
#include "TcpServer.h"
#include "ThreadPool.h"
#include <unistd.h>
#include <iostream>
#include <functional>

using std::cout;
using std::endl;
using std::bind;

//全局变量的线程池对象
ThreadPool *gPool = nullptr;

class MyTask
{
public:
    MyTask(const string &msg, const TcpConnectionPtr &con)
    : _msg(msg)
    , _con(con)
    {

    }
    void process()
    {
        //处理从客户端接收过来的msg,对msg进行业务逻辑的处理
        _msg;
        //线程池在处理好业务逻辑之后，需要将数据发送给EventLoop/Reactor
        //然后由Reactor将数据发送给客户端
        //保证数据处理好之后，将数据发送给Reactor，让Reactor将数据发送给
        //客户端，而不是直接由线程池中线程发个客户端
        //
        //线程池中线程处理好业务逻辑之后，需要通知EventLoop/Reactor，这样
        //Reactor才能去接受数据，不然有可能数据从线程池发过来的时候，
        //Reactor没有接受到
        //线程池中的线程需要与Reactor的线程之间进行通信？
        //解决方案：可以使用eventfd在进程或者线程之间进行通信。
        _con->sendInLoop(_msg);
        //线程池中的线程处理好业务逻辑之后，需要将数据发给Reactor，但是
        //其实使用的是TcpConnection的对象进行发送的，那么处理好之后的数据
        //_msg其实还只在TcpConnection中，要想将数据发给Reactor，必须要
        //让TcpConnection知道EVentLoop存在，所以在TcpConnection中增加了
        //EVentLoop的指针，这样就可以让TcpConnection知道EventLoop的存在
    }
private:
    string _msg;
    TcpConnectionPtr _con;
};

//连接建立
void onNewConnection(const TcpConnectionPtr &con)
{
    cout << con->toString() << " has connected!!!" << endl;
}

//消息到达
void onMessage(const TcpConnectionPtr &con)
{
    //接收客户端的数据
    string msg = con->receive();
    cout << ">>>>recv msg from client " << msg << endl;

    //业务逻辑的处理如果比较复杂，可以业务逻辑的处理交个线程池

    MyTask task(msg, con);
    gPool->addTask(bind(&MyTask::process, task));
}

//连接断开
void onClose(const TcpConnectionPtr &con)
{
    cout << con->toString() << " has closed!!!" << endl;
}

void test()
{
    ThreadPool pool(4, 10);
    pool.start();//工作线程创建出来，并且阻塞等待任务的到来
    gPool = &pool;

    TcpServer server("127.0.0.1", 8888);
    //三个回调一起注册
    server.setAllCallback(std::move(onNewConnection)
                          , std::move(onMessage)
                          , std::move(onClose));
    server.start();
}

int main(int argc, char **argv)
{
    test();
    return 0;
}

